#ifndef RTREACTORBASE_H
#define RTREACTORBASE_H

#include "RtDebug.h"
#include "RtReactorInterface.h"
#include "RtUtilClasses.h"
#include "RtEventQueueBase.h"
#include "RtObserver.h"

#ifdef RT_WIN32
#include <map>
#endif // RT_WIN32

class CRtReactorBase;
class CRtTimerQueueBase;

class CRtEventHandlerRepository
{
public:
	CRtEventHandlerRepository();
	~CRtEventHandlerRepository();

	RtResult Open();
	RtResult Close();

	struct CElement
	{
		IRtEventHandler *m_pEh;
		IRtEventHandler::MASK m_Mask;

		CElement(IRtEventHandler *aEh = NULL,
				 IRtEventHandler::MASK aMask = IRtEventHandler::NULL_MASK)
			: m_pEh(aEh), m_Mask(aMask)
		{
		}

		void Clear()
		{
			m_pEh = NULL; 
			m_Mask = IRtEventHandler::NULL_MASK;
		}

		BOOL IsCleared() const { return m_pEh == NULL; }
	};

	/**
	 * If success:
	 *    if <aFd> is found, return RT_OK;
	 *    else return RT_ERROR_NOT_FOUND;
	 */
	RtResult Find(RT_HANDLE aFd, CElement &aEle);

	/**
	 * If success:
	 *    if <aFd> is found, return RT_ERROR_FOUND;
	 *    else return RT_OK;
	 */
	RtResult Bind(RT_HANDLE aFd, const CElement &aEle);
	
	/**
	 * If success:
	 *    return RT_OK;
	 */
	RtResult UnBind(RT_HANDLE aFd);

	BOOL IsVaildHandle(RT_HANDLE aFd)
	{
#ifdef RT_WIN32
		if (aFd != RT_INVALID_HANDLE)
#else
		if (aFd >= 0 && aFd < m_nMaxHandler)
#endif // RT_WIN32
			return TRUE;
		else
			return FALSE;
	}

#ifndef RT_WIN32
	int GetMaxHandlers()
	{
		return m_nMaxHandler;
	}

	CElement* GetElement()
	{
		return m_pHandlers;
	}
#endif // !RT_WIN32

#ifndef RT_WIN32
	static RtResult SetRlimit(int aResource, int aMaxNum, int &aActualNum);
#endif // !RT_WIN32

	int FillFdSets(fd_set &aFsRead, fd_set &aFsWrite, fd_set &aFsException);

private:
#ifdef RT_WIN32
	typedef std::map<RT_HANDLE, CElement> HandlersType;
	HandlersType m_Handlers;
#else
	CElement *m_pHandlers;
	int m_nMaxHandler;
#endif // RT_WIN32
};


// base class for rector, 
// we have to inherit from <CRtEventQueueUsingMutex> because we 
// will over write PostEvent() to do NotifyHandler().
class /*RT_API_EXPORT*/ CRtReactorBase 
	: public IRtReactor
	, public CRtStopFlag
	, public CRtEventQueueUsingMutex 
{
public:
	CRtReactorBase(PROPERTY aProperty = NULL_PROPERTY);
	virtual ~CRtReactorBase();

	// interface IRtReactor
	virtual RtResult Open();

	virtual RtResult RegisterHandler(
		IRtEventHandler *aEh, 
		IRtEventHandler::MASK aMask);

	virtual RtResult RemoveHandler(
		IRtEventHandler *aEh, 
		IRtEventHandler::MASK aMask = IRtEventHandler::ALL_EVENTS_MASK);

	virtual RtResult Close();

	// interface IRtTimerQueue
	virtual RtResult ScheduleTimer(IRtTimerHandler *aTh, 
					  LPVOID aArg,
					  const CRtTimeValue &aInterval,
					  DWORD aCount);

	virtual RtResult CancelTimer(IRtTimerHandler *aTh);

	// interface IRtEventQueue
	virtual RtResult SendEvent(IRtEvent *aEvent);
	virtual RtResult PostEvent(
		IRtEvent *aEvent, 
		EPriority aPri = IRtReactor::EPRIORITY_NORMAL);
	virtual DWORD GetPendingEventsCount();

	RtResult ProcessHandleEvent(
		RT_HANDLE aFd, 
		IRtEventHandler::MASK aMask, 
		RtResult aReason,
		BOOL aIsNotify,
		BOOL aDropConnect = FALSE);

protected:
	RtResult ProcessTimerTick();

	virtual void OnHandleRemoved(RT_HANDLE aFd) = 0;
	virtual RtResult OnHandleRegister(
		RT_HANDLE aFd, 
		IRtEventHandler::MASK aMask, 
		IRtEventHandler *aEh) = 0;

	CRtEnsureSingleThread m_Est;
	CRtTimerQueueBase *m_pTimerQueue;

private:
	RtResult RemoveHandleWithoutFinding_i(
		RT_HANDLE aFd, 
		const CRtEventHandlerRepository::CElement &aHe, 
		IRtEventHandler::MASK aMask);

protected:
	CRtEventHandlerRepository m_EhRepository;

#ifdef RT_WIN32
	// These two variables are used to check overlapping case of 
	// CRtReactorBase::ProcessHandleEvent() under windows platform.
	BOOL m_bExclusive;
	BOOL m_bOverlapped;
#endif
};


// inline functions
inline RtResult CRtEventHandlerRepository::Find(RT_HANDLE aFd, CElement &aEle)
{
#ifdef RT_WIN32
	RT_ASSERTE_RETURN(IsVaildHandle(aFd), RT_ERROR_INVALID_ARG);
	HandlersType::iterator iter = m_Handlers.find(aFd);
	if (iter == m_Handlers.end())
		return RT_ERROR_NOT_FOUND;
	else {
		aEle = (*iter).second;
		RT_ASSERTE(!aEle.IsCleared());
		return RT_OK;
	}
#else
	// CAcceptor maybe find fd after closed when program shutting down.
	if (!m_pHandlers)
		return RT_ERROR_NOT_INITIALIZED;
	RT_ASSERTE_RETURN(IsVaildHandle(aFd), RT_ERROR_INVALID_ARG);

	CElement &eleFind = m_pHandlers[aFd];
	if (eleFind.IsCleared()) 
		return RT_ERROR_NOT_FOUND;
	else {
		aEle = eleFind;
		return RT_OK;
	}
#endif // RT_WIN32
}

inline RtResult CRtEventHandlerRepository::Bind(RT_HANDLE aFd, const CElement &aEle)
{
	RT_ASSERTE_RETURN(IsVaildHandle(aFd), RT_ERROR_INVALID_ARG);
	RT_ASSERTE_RETURN(!aEle.IsCleared(), RT_ERROR_INVALID_ARG);

#ifdef RT_WIN32
	CElement &eleBind = m_Handlers[aFd];
#else
	RT_ASSERTE_RETURN(m_pHandlers, RT_ERROR_NOT_INITIALIZED);
	CElement &eleBind = m_pHandlers[aFd];
#endif // RT_WIN32
	
	BOOL bNotBound = eleBind.IsCleared();
	eleBind = aEle;
	return bNotBound ? RT_OK : RT_ERROR_FOUND;
}

inline RtResult CRtEventHandlerRepository::UnBind(RT_HANDLE aFd)
{
	RT_ASSERTE_RETURN(IsVaildHandle(aFd), RT_ERROR_INVALID_ARG);

#ifdef RT_WIN32
	m_Handlers.erase(aFd);
#else
	RT_ASSERTE_RETURN(m_pHandlers, RT_ERROR_NOT_INITIALIZED);
	m_pHandlers[aFd].Clear();
#endif // RT_WIN32
	
	return RT_OK;
}

#endif // !RTREACTORBASE_H
